package continuum.service.security;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import continuum.db.dao.Dao;
import continuum.db.dao.util.QueryParameter;
import continuum.db.exceptions.DaoException;
import continuum.db.schema.embeddables.SecurityDetails;
import continuum.db.schema.entities.Employee;

@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

	private static final Logger log = Logger
			.getLogger(UserDetailsServiceImpl.class);

	@Resource
	private Dao<Employee, Integer> employeeDao;

	@Override
	public UserDetails loadUserByUsername(final String username)
			throws UsernameNotFoundException {

		if (username.equals("admin")) {
			log.warn("Admin login attempted");
			List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
			authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
			authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
			return new User("admin", "admin", true, true, true, true,
					authorities);
		} else {
			return generateUserByDatabase(username);
		}

	}

	@Transactional(readOnly = true)
	private User generateUserByDatabase(final String username)
			throws UsernameNotFoundException {

		try {
			List<Employee> employees = employeeDao
					.selectAllByField(new QueryParameter("username", username));
			if (employees.isEmpty()) {
				throw new UsernameNotFoundException("No user found with name: "
						+ username);
			} else {
				SecurityDetails details = employees.get(0).getSecurityDetails();
				List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
				for (String s : details.getRoles().split(",")) {
					authorities.add(new SimpleGrantedAuthority(s));
				}
				return new User(username, details.getPassword(),
						details.isActive(), details.isActive(),
						details.isActive(), details.isActive(), authorities);
			}
		} catch (DaoException e) {
			throw new UsernameNotFoundException(
					"Issue connecting to database to authenticate user: "
							+ username, e);
		}
	}

	public Dao<Employee, Integer> getEmployeeDao() {
		return employeeDao;
	}

	public void setEmployeeDao(Dao<Employee, Integer> employeeDao) {
		this.employeeDao = employeeDao;
	}
}
